/** @file RGB color handling */
#pragma once

#include "util.hpp"
#include "core/error.hpp"

/** A RGB color */
class RGB
{
public:

  float r,g,b;

  /** Check for nans color
   * @return if there are nans */
  inline bool hasnans() const
  {
    return isnan(r) || isnan(g) || isnan(b);
  }

  /** Construct */
  RGB() {}

  /** Construct
   * @param R red
   * @param G green
   * @param B blue */
  RGB(const float R, const float G, const float B) : r(R), g(G), b(B)
  {
    assert(!hasnans());
  }

  inline RGB operator+(const RGB& o) const
  {
    return RGB(r+o.r, g+o.g, b+o.b);
  }

  inline void operator+=(const RGB& o)
  {
    r += o.r;
    g += o.g;
    b += o.b;
    assert(!hasnans());
  }

  inline RGB operator-(const RGB& o) const
  {
    return RGB(r-o.r, g-o.g, b-o.b);
  }

  inline void operator-=(const RGB& o)
  {
    r -= o.r;
    g -= o.g;
    b -= o.b;
    assert(!hasnans());
  }

  inline RGB operator*(const RGB& o) const
  {
    return RGB(r*o.r, g*o.g, b*o.b);
  }

  inline void operator*=(const RGB& o)
  {
    r *= o.r;
    g *= o.g;
    b *= o.b;
    assert(!hasnans());
  }

  inline RGB operator*(const float o) const
  {
    return RGB(r*o, g*o, b*o);
  }

  inline RGB operator/(const RGB& o) const
  {
    return RGB(r/o.r, g/o.g, b/o.b);
  }

  inline void operator/=(const RGB& o)
  {
    r /= o.r;
    g /= o.g;
    b /= o.b;
    assert(!hasnans());
  }

  inline RGB operator/(const float o) const
  {
    const float inv = 1.f/o;
    return RGB(r*inv, g*inv, b*inv);
  }

  inline void operator/=(const float o)
  {
    const float inv = 1.f/o;
    r *= inv;
    g *= inv;
    b *= inv;
    assert(!hasnans());
  }

  inline void operator*=(const float o)
  {
    r *= o;
    g *= o;
    b *= o;
    assert(!hasnans());
  }

  inline bool operator==(const RGB& o) const
  {
    return o.r==r && o.g==g && o.b==b;
  }

  inline float operator[](const int i) const
  {
    switch(i)
      {
      case 0:
	return r;
      case 1:
	return g;
      case 2:
	return b;
      default:
	error(asString(i)+" is not a valid RGB index");
      }
    return 0;
  }
  inline float& operator[](const int i)
  {
    switch(i)
      {
      case 0:
	return r;
      case 1:
	return g;
      case 2:
	return b;
      default:
	error(asString(i)+" is not a valid RGB index");
      }
  }
    
};

inline RGB operator*(const float a, const RGB& b)
{
  return b*a;
}
